home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Collections: Bavarian
/
Bavarian #197 (19xx)(APS Electronic).zip
/
Bavarian #197 (19xx)(APS Electronic).adf
/
ALisp.doc
< prev
next >
Wrap
Lisp/Scheme
|
1988-06-01
|
21KB
|
446 lines
Weeze, 31.3.1990
AmigaLisp
---------
AmigaLisp ist ein einfacher, in C (Aztec C Vers. 3.4) geschriebener Lisp -
Interpreter. Der Befehlssatz von AmigaLisp orientiert sich an XLISP bzw. an
Common - Lisp.
Der Quelltext ist dokumentiert und relativ leicht zu verstehen, so daß C -
Programmierer Lisp durch Studium des Interpreters leicht erlernen können.
Ich selbst habe AmigaLisp programmiert, um mir den Einstieg in Lisp zu
vereinfachen.
Der Interpreter kann vom CLI aus mit dem Kommando 'AmigaLisp <PrgName>'
geladen und gestartet werden. Dabei bezeichnet der optionale Parameter
PrgName den Quelltext eines Lispprogramms, das vom Interpreter direkt
nachgeladen und gestartet werden soll.
Die Benutzerschnittstelle des Interpreters besteht aus zwei Fenstern.
Im Dialogfenster wird die Sitzung protokolliert. Hier erscheinen alle
Ein- und Ausgaben. Bitte geben Sie nicht direkt ins Dialogfenster ein,
sondern benutzen den Editor :
Um die Eingaben freundlicher zu gestalten, ist das zweite Fenster ein
kleiner Editor. Hier geben Sie Ihre Befehle ein, die anschließend ins
Dialogfenster übertragen werden. Mit den Cursortasten können Sie in diesem
Fenster frei herumfahren. Außerdem verfügt diese Eingaberoutine über eine
History. In ihr können Sie mit <shift><cursor up> bzw. <shift><cursor down>
beliebig blättern.
Da das Zeichen "'" häufig benutzt wird, wurde es auf die Taste rechts vom
"ß" gelegt.
Nun können Sie den Dialog mit dem Interpreter aufnehmen.
Tippen Sie z.B. ein : (+ 3 5 2)
Sie erhalten vom System die Antwort 10. (+ 3 5 2) entspricht also der
mathematischen Schreibweise 3 + 5 + 2. Lisp benutzt die Polnische
Notation (Präfix Notation), bei der die durchzuführende Funktion vor ihre
Argumente gestellt sein muß.
Lisp bedeutet Listprocessor, also Listenverarbeiter. Eine Liste beginnt mit
einer Klammer '(' und endet mit einer geschlossenen ')'. Eine Liste kann
beliebig viele Elemente besitzen, die auch selbst wieder Listen sein können.
Soll nun eine Liste ausgewertet (evaluiert) werden, dann interpretiert Lisp
das erste Listenelement als Befehl und weist ihm die restlichen
Listenelemente als Parameter zu. Bei dem Beispiel ist also '+' als erstes
Listenelement der Befehl, dem die Werte 3, 5 und 2 als Parameter zugewiesen
werden.
Ein Lisp Programm ist letztlich eine Aneinanderreihung solcher Listen.
Um sinnvoll programmieren zu können, benötigt man Variablen und Konstanten.
Lisp - Variablen können beliebig lange Zeichenketten sein. Sie werden
Symbole genannt. Konstanten sind (Bruch-) Zahlen, Strings und
Wahrheitswerte ('t' für true und nil oder '()' für false ).
Strings sind Zeichenketten, die durch Anführungszeichen gekennzeichnet sind:
"Dies ist ein String"
Tippt man eine solche Konstante ein, dann erhält man die Eingabe vom
Interpreter als Ausgabe zurück : Konstanten evaluieren zu sich selbst.
Werden dagegen Symbole ausgewertet, dann evaluieren sie zu ihrem Inhalt.
Alle Parameter eines Befehls werden vor der Übergabe stets ausgewertet, wenn
dies nicht verboten wird. (siehe quote oder ').
An Symbole können sowohl Konstante wie auch Listen gekettet sein. Eine Zu-
weisung an ein Symbol geschieht mit der setq - Funktion.
Schreibt man in Basic variable=10, so entspricht dies dem Lisp-Term
(setq variable 10)
Alle Elemente einer Liste sollen doch ausgewertet werden, werden Sie jetzt
vielleicht denken. An 'variable' hängt aber noch überhaupt kein Wert.
Deshalb wird bei dem Befehl setq der erste Parameter nicht ausgewertet.
Gleichbedeutend ist diese Schreibweise :
(set (quote variable) 10)
Der set-Befehl (Man spricht von der Primitive set) entspricht der Primitive
setq , jedoch wird hier auch der erste Parameter ausgewertet. Quote gibt
seinen Parameter unausgewertet zurück. Wird also (quote variable) evaluiert,
so ergibt sich dafür der Wert 'variable'. Da quote sehr häufig benutzt wird,
kann der Befehl so abgekürzt werden :
(set 'variable 10)
In Lisp wird eine Liste durch einen Baum intern dargestellt :
(a b c d) entspricht : /\
a /\ / und \ bezeichnen Zeiger
b /\
c ()
Für ((a b) (c d)) ergibt sich entsprechend :
/\ Die Zeigerpaare sind im
/\ /\ Interpreter durch die Struk-
a /\ /\ () tur paar dargestellt. Die
b () c /\ Blätter des Baumes durch
d () atom.
Der rechtsseitige Baum ist zur Standardliste erklärt worden. Einem rechten
Zeiger kann also nur ein weiteres Zeigerpaar oder () folgen. Sollte dort
aber ein Atom (also ein Endknoten oder Blatt) stehen, dann wird dies bei der
Ausgabe durch einen Punkt mitgeteilt. Solche Bäume können nicht ausgewertet
werden, sind als Datenstruktur aber zulässig. Bei der Eingabe kann durch
Setzen solcher Punkte ein entsprechender Aufbau erzwungen werden.
(a.(b.c)) wir so dargestellt : /\
a /\
b c
Um Programme schreiben zu können, benötigt man bedingte Verzweigungen und
Wiederholungsanweisungen.
Bedingte Verzweigungen werden mit dem cond-Befehl ermöglicht :
(cond (Bedingung1 Ausdruck1 [Ausdruck2 ...])
(Bedingung2 Ausdruck1 [Ausdruck2 ...])
usw.
)
In einer cond - Anweisung können beliebig viele Bedingungen auftreten. Die
Bedingungen müssen zu einem Wahrheitswert auswerten. Die Ausdrücke, die der
ersten erfüllten Bedingung folgen, werden ausgewertet. Es dürfen beliebig
viele Ausdrücke folgen.
Schleifen :
Es gibt drei Schleifenarten. In der while - Schleife wird das
Abbruchkriterium zum Schleifenbeginn abgefragt. In der do-Schleife geschieht
dies am Ende. Die count-Schleife wird verwendet, wenn die Anzahl der
Schleifendurchläufe anfangs bereits feststeht.
Die Schleifen haben die Syntax
(while <Bedingung> <Ausdrücke>) bzw. (do <Bedingung> Ausdrücke)
und
(count <n> <Ausdrücke>) wobei n die Anzahl der Durchläufe angibt.
Bedingung kann ein beliebiger Lisp-Term sein, der zu einem Wahrheitswert
evaluiert.
Das Funktionskonzept :
('(lambda (Parameter) Ausdrücke) Werte)
Erhält der Interpreter nach Auswertung des ersten Listenelements keinen
Verweis auf einen Befehl, sondern eine Liste, deren erstes Element das
Symbol lambda ist, dann kettet dieser die angegebenen Werte an die lokalen
(optionalen) Parameter und wertet anschließend die Ausdrücke aus.
Mit dem Befehl defun wird ein solcher Lambda-Term an ein Symbol gekettet,
das nun als Funktion benutzt werden kann :
(setq addiere '(lambda (a b) (+ a b))) entspricht somit
(defun addiere (a b) (+ a b))
(addiere 4 6) liefert das Ergebnis 10.
In der Parameterliste können noch die Symbole &aux und &rest auftreten.
&aux : Die lokalen Symbole , die einem &aux folgen, werden nicht mit Werte
der Werteliste initialisiert.
&rest: Das nach &rest folgende Symbol erhält als Wert die Liste allert noch
nicht zugeordneter Werte.
Funktionen können selbstverständlich rekursiv sein.
Neben den Lambda - Termen gibt es noch Macro-Terme. Das Symbol lambda ist
hier durch macro ersetzt. Eine Funktion, mit der Macro-Terme an Variablen
gekettet werden, entspricht defun und heißt defmacro.
Macro-Terme werten die Werte nicht aus, bevor sie an die lokalen Symbole
gekettet werden. (Lambda - Terme tun dies !). Außerdem wird das Ergebnis
eines solchen Terms nochmal ausgewertet. Mit dieser Technik lassen sich
reine Textersätze realisieren.
Mit defun definierte Funktionen (oder Macros) können rekursiv sein.
Neben Funktionen bietet der Befehl progn die Möglichkeit, zusammengehörige
Anweisungslisten auch formal zu einer Liste zusammenzufassen.
(progn <Anweisung><Anweisung>... ) ist formal gleichbedeutend mit
<Anweisung><Anweisung>...
Nur nach der letzten Anweisung kann hier eine Garbage-Collection
durchgeführt werden. Damit kann man bei ausreichender Speichergröße
die Geschwindigkeit von Programmen steigern.
Es ist verständlich, wenn nach diesem Grobüberblick noch Fragen offen sind.
Ich verweise hier auf die Beispielprogramme und den Quelltext des
Interpreters.
Die Befehle von AmigaLisp :
Arithmetik :
Allgemeine Operatoren : +,-,* und /
Operatoren für Ganzzahlen: div := Ganzzahldivision
mod := Rest der Ganzzahldivision [%]
Operatoren für reelle Zahlen : cast := Zahl in Ganzzahl umwandeln
Fließkommafunktionen : (sin X),(cos X),(atan X),(sqrt X),
(exp X),(log X)
In der Datei setup.lsp sind weitere elementare Funktionen definiert.
Typumwandlungen : (float X) : transformiert X in Fließkommadarstellung
(nofloat X): X wird in eine Bruchzahl gewandelt
Zum Zahlenkonzept von AmigaLisp :
Bruchrechnung ist eine der Besonderheiten von AmigaLisp. Dazu können
Zahlen sowohl in einer Fließkomma- als auch in expliziter Bruchschreib-
weise dargestellt werden. Brüche werden automatisch gekürzt.
Da diese intern durch zwei Integerzahlen beschrieben werden, ist der so
darstellbare Zahlenbereich allerdings sehr eingeschränkt. Bei ev. Über-
läufen werden aus Effiziensgründen keine Fehlermeldungen ausgegeben.
Deshalb sollten in kritischen Anwendungen Fließkommazahlen benutzt
werden.
Treten in einer Berechnung sowohl Fließkomma- als auch Bruchzahlen auf,
so wird eine Typumwandlung vorgenommen und das Ergebnis liegt als Fließ-
kommazahl vor.
Die Syntax der Zahlendarstellung sei durch folgende EBNF beschrieben :
AmigaLisp-Zahl ::= Bruchzahl | Fließkommazahl.
BruchZahl ::= GanzeZahl [ "/" NatürlicheZahl ].
GanzeZahl ::= [-] NatürlicheZahl.
Fließkommazahl ::= GanzeZahl "." NatürlicheZahl [ "e" | "E" ] GanzeZahl.
Ziffer ::= 0|1|2|3|4|5|6|7|8|9.
NatürlicheZahl ::= Ziffer { Ziffer }.
Listenbefehle :
(car <Liste>) liefert das erste Listenelement
(cdr <Liste>) liefert die Restliste
(cadr <Liste>) liefert das zweite Listenelement
(nth <n> <Liste>) liefert das n-te Listenelement
(cons <Ausdruck1> <Ausdruck2>) richtet ein Zeigerpaar ein, dessen linker
Zeiger auf den ausgewerteten Ausdruck1 und dessen rechter
Zeiger auf den ausgewerteten Ausdruck2 zeigt.
(list <Ausdruckliste>) evaluiert alle Ausdrücke und fügt sie zu einer Liste
zusammen
(null <Ausdruck>) wertet aus zu t, wenn Ausdruck zu () auswertet.
(listp<Ausdruck>) wertet aus zu t, wenn Ausdruck zu einer Liste evaluiert.
(atom <Ausdruck>) wertet aus zu t, wenn Ausdruck zu einem Atom auswertet.
Vergleichsfunktionen :
Für Zahlen und Strings : >,>=,<,<= und eql (entspricht ==)
Für Atome (Konstanten,Symbolnamen) : eq (Test auf Gleichheit)
Allgemein : equal (Test auf Gleichheit)
Achtung : bei eq und equal müssen die Daten formal gleich sein,
d.h. 1.0 ist ungleich 1
Logische Funktionen :
(and <Ausdruckliste>) wertet gg. alle Ausdrücke aus und gibt t zurück, wenn
alle zu t evaluieren.
(or <Ausdruckliste>) wertet Ausdrücke solange aus, bis einer zu t evaluiert
(not <Ausdruck>) Negiert den evaluierten Ausdruck.
Stringfunktionen :
(strcat <Ausdruck1> <Ausdruck2>) evaluiert die Ausdrücke und fügt die so
entstandenen Strings zu einem zusammen.
(strlen <Ausdruck>) evaluiert den Ausdruck und ermittelt die Länge des so
entstandenen Strings
(substr <Ausdruck> <Anfang> <Länge (optional>) entspricht MID$ in Basic
(ascii <Ausdruck>) Wandelt den Anfangsbuchstaben eines Strings (des
evaluierten Ausdrucks) in eine Zahl um.
(chr <Zahl>) Wandelt die Zahl in einen einelementigen String um.
Dateifunktionen :
(open <String>): Öffnet die durch den String bezeichnete Datei zum
Schreiben.
(open <String>): Öffnet die durch den String bezeichnete Datei zum
Lesen (noch nicht implementiert)
(princdat <Ausdruck>): In die geöffnete Schreibdatei wird das Ergebnis
der Ausdruck-Auswertung geschrieben. (siehe princ)
(readdat <String>): Liest alle Einträge einer Datei und gibt sie als
Liste verkettet zurücke.
(killfile <String>): Löscht die bezeichnete Datei. Es wird zurückgegeben,
ob die Operation erfolgreich war. (t oder nil)
Bemerkung : Es kann stets nur eine Schreibdatei geöffnet werden.
Beispiel : (openw "df1:testdatei")(princdat "Hallo")(closew) schreibt
den String "Hallo" mit den Anführungsstrichen in die Datei
df1:testdatei.
spezielle Lisp - Funktionen :
(eval <Ausdruck>) Wertet den Ausdruck zweimal aus.
set und setq : siehe oben
kill und killq : inverse Befehle zu set und setq.
Hiermit werden Variablen wieder aus dem System entfernt.
Sie belegen also anschließend keinen Speicherplatz mehr.
Es dürfen (und können) nur globale Variablen gelöscht
werden.
(princ <Ausdruckliste>) Evaluiert die Ausdrücke und gibt sie im Dialog-
fenster aus. Bei reinen Strings werden die Anführungs-
zeichen weggelassen.
(terpri) Die Bildschirmausgabe wird mit einer neuen Zeile fortge-
setzt.
(quote <Ausdruck>) gibt einen Ausdruck unausgewertet zurück.
Ausnahme : Steht vor einem Atom des Ausdrucks ein Komma,
so wird dieses Atom ausgewertet.
Systemfunktionen :
(free) zeigt die Speicherbelegung an. (Auch als Menüpunkt vorhanden)
(varlist) zeigt alle gültigen Symbolnamen an. (ebenfalls Menüpunkt)
(objlist) zeigt alle gültigen Grafikobjektnamen an.(ebenfalls Menüpunkt)
(load <Ausdruck>) wertet Ausdruck aus, der zu einem String evaluieren muß,
und läd die damit bezeichnete Datei von Diskette und be-
ginnt mit der Auswertung dieser Eingabe. Bisher im Ein-
gabepuffer befindliche Daten werden gelöscht.
Die load-Funktion ist auch über ein Menü erreichbar.
(read <Ausdruck optional>) Ist kein Ausdruck angegeben, dann liest read
einen Lisp-Term von der Tastatur und gibt ihn zurück
Ein Ausdruck muß zu einem String auswerten. Dann wird aus
dem String ein Lisp-Term gelesen und zurückgegeben.
(forbid) unterdrückt alle Bildschirmausgaben mit Ausnahme von princ, bis
diese wieder erlaubt werden.
(allow) erlaubt alle Bildschirmausgaben wieder
(random <Zahl>) liefert eine reelle Zufallszahl aus [0,Zahl).
Grafikfunktionen :
AmigaLisp unterstützt das Prinzip der Turtle-Grafik, bei dem eine hier nicht
explizit dargestellte Schildkröte auf dem Ausgabefenster bewegt wird und
gegebenenfalls Spuren hinterläßt. Daneben ist aber auch ein "herkömmlicher"
Grafiktreiber implementiert.
(graphic) Die Grafik wird eingeschaltet.
Um einen flimmerfreien Animationsablauf zu erzielen, werden
zwei Grafikbildschirme installiert, die abwechselnd (bei view)
in den Vordergrung gebracht werden.
Reicht der Speicherplatz im ShipMem für zwei Grafikbereiche nicht
aus, so wird nur einer geöffnet.
(text) Das Grafikfenster wird ausgeschaltet.
Die Befehle graphic und text werden auch für die Vektorgrafik (s.u.) ein-
gesetzt.
(draw a b c d e) - zeichnet eine Linie mit der Farbe des Registers c.
Mit a und b, die zu Wahrheitswerten evaluieren, wird einer von vier
Zeichen modi ausgewählt :
a b Von der aktuellen Position Q(x,y) aus wird die Strecke
----|----
t | t zum Punkt P(d,e) gezeichnet (absolute Koordinaten)
nil | t zum Punkt P(d+x,e+y) gezeichnet (relative Koordinaten)
t | nil zu einem Punkt in der Enfernung e gezeichnet. Die Strecke
| schließt mit der positiven x-Achse den Winkel d ein.
nil | nil zu einem Punkt in der Entfernung e gezeichnet. Die Strecke
| schließt mit der pos. x-Achse den Winkel d+alpha ein, wobei
alpha der letzte benutzte Winkel ist. (Winkelangeben relativ)
Mit diesem Modus können Turtle-Grafikprogramme geschrieben werden. Der
jeweils erreichte Punkt wird zum Startpunkt für die nächste Operation.
Ebenso werden die neuen Winkel festgehalten.
Soll zu einer neuen Position gelangt werden, ohne daß eine Linie gezeich-
net wird, so ist als Farbe -1 anzugeben. In der setup.lsp - Datei sind
einige Symbole vordefiniert, die die Arbeit mit diesem Universalbefehl
erleichtern : KEINE, DUNKEL, WEIß, ROT, GRÜN beziehen sich auf die Farb-
wahl, ABSOLUT, RELATIV, KOORDINATEN und WINKEL auf die Werte von a und b.
Die Startposition ist der Koordinatenursprung, der Startwinkel 0 Grad.
Winkelgrößen werden im Gradmaß angegeben. Um die aktuelle Zeichenposi-
tion/Zeichenwinkel auslesen zu können, gibt der Befehl im Modus KOORDI-
NATEN die Ausgangskoordinaten der Strecke und im Modus WINKEL den Aus-
gangswinkel zurück. Punkte sind Strecken der Länge 0.
Bsp.: (draw ABSOLUT KOORDINATEN WEIß 10 10) - zieht eine Linie zum
Punkt P(10 10).
(draw RELATIV KOORDINATEN KEINE 0 0) - liefert die aktuellen
Koordinaten der Zeichenposition
(draw RELATIV WINKEL KEINE 0 0) - liefert die aktuelle Richtung
(ellipse Farbe x y hradius vradius) - zeichnet eine Ellipse mit Mittel-
punkt P(x,y) in der gewählten Farbe mit den bezeichneten Radien.
(fill Farbe x y) - füllt den Bereich, in dem P(x y) liegt mit der gewählten
Farbe.
(clear) Der Grafikbildschirm wird gelöscht.
Vektorgrafikbefehle:
ALisp ermäglicht die Darstellung von 3D-Gittermodellen.
(defobj name <Liste>) Definiert ein Grafikobjekt bestehend aus Polygon-
zügen, Strecken und Punkten.
Die Liste ist eine Liste der Polygonzüge. Ein Poly-
gonzug ist eine Liste der Eckpunkte.
Ein Eckpunkt ist eine Liste der drei Koordinaten.
Bsp.: (defobj quadrat '(((0 0 0)(0 1 0)(1 1 0)(1 0 0))))
(killo name) Entfernt das Grafikobjekt name wieder aus dem System.
(rotate_x name <Winkel>) Das bezeichnete Grafikobjekt wird um den
(rotate_y name <Winkel>) entsprechenden Winkel um die angegebene Achse
(rotate_z name <Winkel>) gedreht.
(strech name <Koordinatentripel>) Multiplikation aller Koordinaten des
Objekts mit den entsprechenden des Tripels
(put name <Tripel>) verschiebt das Objekt zum angegebenen Punkt.
(color name <Zahl>) Farbregisterdefinition für das Objekt
(setpos name <Tripel>)Definition der Weltkoordinaten des Objekts
(print name) Zeigt das Objekt auf dem Bildschirm
(view) Zeigt alle Objekte an (gesamte 3D-Welt)
Dabei wird das Ausgabe-Fenster gewechselt, so daß
ein flimmerfreier Eindruck entstehen sollte.
Der Interpreter kann durch Anklicken des entsprechenden Menüpunktes
verlassen werden. Die Menüpunkte sind selbsterklärend.
Arbeitsspeicher wird vom Interpreter automatisch angefordert und an die
Bedürfnisse angepaßt. Lisp benötigt viel Speicher. 1 MB RAM ist also
empfehlenswert, jedoch nicht notwendig.
AmigaLisp fängt alle Programmierfehler sicher ab. Nur wird nicht getestet,
ob der Stack für das Interpreterprogramm selbst stets ausreicht.
Finden sehr tiefe Rekursionen in den Lisp-Programmen statt, so muß auch
der Stack für den Interpreter angemessen dimensioniert sein.
Läuft der Stack über, so gelangt der Rechner in einen undefinierten Zustand.
Achtung : Bitte stets für einen genügend großen Stack sorgen !
Auf dieser Diskette befinden sich die folgenden Beispielprogramme:
hanoi.lsp : Türme von Hanoi als Lisp-Programm (type oder ed)
Ausführung mittels 'AmigaLisp hanoi.lsp'
fakul.lsp : Fakultätsberechnung in Lisp
bubble.lsp : Ein Bubblesortalgorithmus in Lisp
insertsort.lsp: Sortieren durch Einfügen
eliza.lsp : Eine Demo der KI (oder auch nicht...)
demo.lsp : Demonstration der Vektorgrafikbefehle
disk.lsp : - " -
pharao.lsp : Grafikdemo
pythagoras.lsp: - " -
palindrom.lsp : Plalindromerkennung mit zwei Listen.
(Ein Palindrom ist eine symmetrische Zeichenkette)
Der Quelltext des Interpreters liegt mit den Dateien modul1, modul2,
modul3.c, modul4.c, modul5.c, modul6.c, modul7.c und modul8.c vor.
modul1 : Funktionen zur Speicherverwaltung, Ein- und Ausgabe von Listen
modul2 : Variablenverwaltung, Prozedur zum Auswerten von Lisp-Ausdrücken
modul3 : Elementare Lisp-Operationen
modul4 : Kontrollstrukturen
modul5 : Stringbefehle
modul6 : Grafikbefehle
modul7 : Vektorgrafikroutinen
modul8 : Benutzeroberfläche
Viel Spaß mit AmigaLisp.
Steffen Goebbels